package ooo.reindeer.commons.utils;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SerialNumberUtil {

    final static AtomicInteger sequence = new AtomicInteger(0);
    final static ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
    final static String FIX=(int)Math.floor(1+Math.random()*(999999-1+1))+"-";
    static String identification = "";
    static TimeUnit periodicUnit = TimeUnit.SECONDS;
    static long periodic = 1;
    final static AtomicInteger timestamp = new AtomicInteger(generateTimestamp());
    static String prefix;
    static Thread updateTimestampThread = new Thread(new Runnable() {

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    periodicUnit.sleep(periodic);
                    LOCK.writeLock().lock();
                    timestamp.set(generateTimestamp());
                    updatePrefix();
                    sequence.set(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    LOCK.writeLock().unlock();
                }
            }
        }
    });

    static {

        updateTimestampThread.setName("Update-Timestamp-Thread");
        updateTimestampThread.setDaemon(true);
        updateTimestampThread.start();
        updatePrefix();
    }

    private static int generateTimestamp() {
        return (int) (System.currentTimeMillis() / TimeUnit.MILLISECONDS.convert(periodic, periodicUnit));
    }

    public static String getIdentification() {
        return identification;
    }

    public static void setIdentification(String identification) {
        if (SerialNumberUtil.identification.isEmpty()) {
            SerialNumberUtil.identification = identification;
            updatePrefix();
        } else {
            throw new RuntimeException("Do not repeat settings Identification");
        }
    }

    public static long getPeriodic() {
        return periodic;
    }

    public static void setPeriodic(long periodic) {
        SerialNumberUtil.periodic = periodic;
    }

    public static TimeUnit getPeriodicUnit() {
        return periodicUnit;
    }

    public static void setPeriodicUnit(TimeUnit periodicUnit) {
        SerialNumberUtil.periodicUnit = periodicUnit;
    }

    public static String getSerialNumber() {
        try {
            LOCK.readLock().lock();
            String sn= prefix + (sequence.getAndIncrement() + 1000000000);

            return sn;
        } finally {
            LOCK.readLock().unlock();
        }
    }

    public static int getTimestamp() {
        return timestamp.get();
    }

    private static void updatePrefix() {
        LOCK.writeLock().lock();
        if (identification.isEmpty()) {
            prefix = FIX+timestamp.get() + "-";
        } else {
            prefix = identification + "-" + FIX +timestamp.get() + "-";
        }
        LOCK.writeLock().unlock();
    }

}
